package com.gmall.rabbitmq.consumer.service;

import com.gmall.rabbitmq.config.RabbitMQConfig_Reliable;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.io.IOException;

@Component
public class RabbitMQServive_Reliable {

    @Autowired
    RedisTemplate redisTemplate;

    @RabbitListener(queues = RabbitMQConfig_Reliable.Queue_Reliable,concurrency = "1")
    public void receive_ReliableMessage(Channel channal, Message message,String msg){
        long deliveryTag = message.getMessageProperties().getDeliveryTag();
        String messageId = message.getMessageProperties().getMessageId();

        System.out.println("------ Queue_Reliable Start-------");
        System.out.println("MessageID:" + messageId);
        System.out.println("MessageBody:" + new String(message.getBody()));
        System.out.println("msg:" + msg);
        System.out.println("------ Queue_Reliable End-------");

        //重复消费

        //判断Redis中有没有messageId ，如果没有，第一次消费，执行业务逻辑，消费成功后，将messageId存入Redis
        //或者从数据库中查询消息ID是否存在 select * from t_message_log where message_id = 'xxx'

        //如果存在，则不进行处理，如果不存在，则进行处理
        //如果处理成功，则进行ACK，如果处理失败，则进行NACK，并且设置requeue为false
        String messageId_from_redis = (String)redisTemplate.opsForValue().get("messageId:" + messageId);

        if(!StringUtils.isEmpty(messageId_from_redis)){//存在
            System.out.println("------ 重复消费，不进行处理-------");
            try {
                channal.basicAck(deliveryTag,false);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }else{
            try {
                System.out.println("------ 执行业务逻辑 Start-------");
                //int i = 10/0;//网络 抖动
                System.out.println("------ 执行业务逻辑 End-------");
                //保存到数据库或者Redis中
                redisTemplate.opsForValue().set("messageId:" + messageId,messageId);
                //发送ACK，通知RabbitMQ删除消息
                channal.basicAck(deliveryTag,false);
            } catch (Exception e) {
                try {
                    /**
                     * long deliveryTag
                     * boolean multiple
                     * boolean requeue 重新进队列
                     * 如果处理成功，则进行ACK，如果处理失败，则进行NACK，并且设置requeue为false
                     */
                    channal.basicNack(deliveryTag,false,true);
                } catch (IOException ex) {
                    throw new RuntimeException(ex);
                }
            }
        }
    }

}
